package com.witmore.ftp.web.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.witmore.ftp.db.entity.FtpUserDO;
import com.witmore.ftp.db.mapper.FtpUserMapper;
import com.witmore.ftp.web.config.FtpProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ftpserver.ftplet.*;
import org.apache.ftpserver.usermanager.impl.BaseUser;
import org.apache.ftpserver.usermanager.impl.ConcurrentLoginPermission;
import org.apache.ftpserver.usermanager.impl.TransferRatePermission;
import org.apache.ftpserver.usermanager.impl.WritePermission;
import org.apache.ftpserver.usermanager.UsernamePasswordAuthentication;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * 自定义用户管理器
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CustomUserManager implements UserManager {

    private final FtpUserMapper ftpUserMapper;
    private final FtpProperties ftpProperties;

    @Override
    public User getUserByName(String username) throws FtpException {
        log.debug("Getting user by name: {}", username);

        // 从数据库中查找用户
        User dbUser = getUserFromDatabase(username);
        if (dbUser != null) {
            return dbUser;
        }

        log.warn("User not found: {}", username);
        return null;
    }


    /**
     * 从数据库中获取用户
     */
    private User getUserFromDatabase(String username) {
        try {
            LambdaQueryWrapper<FtpUserDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(FtpUserDO::getUsername, username)
                       .eq(FtpUserDO::getEnabled, true)
                       .eq(FtpUserDO::getIsDeleted, 0);
            
            FtpUserDO ftpUser = ftpUserMapper.selectOne(queryWrapper);
            if (ftpUser == null) {
                return null;
            }

            BaseUser user = new BaseUser();
            user.setName(ftpUser.getUsername());
            user.setPassword(ftpUser.getPassword());
            
            // 设置用户主目录 - 修复路径拼接问题
            String rootDir = ftpProperties.getServer().getRootDirectory();
            String homeDir = ftpUser.getHomeDirectory();
            
            // 构建完整的主目录路径
            String fullHomeDir;
            if (homeDir != null && !homeDir.isEmpty()) {
                // 如果配置了相对路径，拼接到根目录
                if (homeDir.startsWith("/")) {
                    fullHomeDir = rootDir + homeDir;
                } else {
                    fullHomeDir = rootDir + "/" + homeDir;
                }
            } else {
                fullHomeDir = rootDir + "/" + username;
            }
            
            // 确保目录存在
            File userHomeDir = new File(fullHomeDir);
            if (!userHomeDir.exists()) {
                boolean created = userHomeDir.mkdirs();
                if (created) {
                    log.info("Created user home directory: {}", userHomeDir.getAbsolutePath());
                } else {
                    log.error("Failed to create user home directory: {}", userHomeDir.getAbsolutePath());
                }
            }
            
            // 创建用户目录结构
            createUserDirectoryStructure(userHomeDir, username);
            
            user.setHomeDirectory(userHomeDir.getAbsolutePath());
            log.info("User {} home directory set to: {}", username, userHomeDir.getAbsolutePath());
            user.setEnabled(ftpUser.getEnabled());

            // 设置权限
            List<Authority> authorities = new ArrayList<>();
            
            // 写权限
            if (ftpUser.getWritePermission() != null && ftpUser.getWritePermission()) {
                authorities.add(new WritePermission());
            }
            
            // 并发连接权限
            int maxConnections = ftpUser.getMaxConnections() != null ? ftpUser.getMaxConnections() : 5;
            int maxConnectionsPerIp = ftpUser.getMaxConnectionsPerIp() != null ? ftpUser.getMaxConnectionsPerIp() : 2;
            authorities.add(new ConcurrentLoginPermission(maxConnections, maxConnectionsPerIp));
            
            // 传输速率权限（无限制）
            authorities.add(new TransferRatePermission(0, 0));
            
            user.setAuthorities(authorities);

            log.info("Loaded user from database: {}", username);
            return user;
        } catch (Exception e) {
            log.error("Error loading user from database: {}", username, e);
            return null;
        }
    }

    @Override
    public String[] getAllUserNames() throws FtpException {
        List<String> usernames = new ArrayList<>();
        
        // 从数据库中获取所有启用的用户
        try {
            LambdaQueryWrapper<FtpUserDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(FtpUserDO::getEnabled, true)
                       .eq(FtpUserDO::getIsDeleted, 0)
                       .select(FtpUserDO::getUsername);
            
            List<FtpUserDO> ftpUsers = ftpUserMapper.selectList(queryWrapper);
            for (FtpUserDO ftpUser : ftpUsers) {
                usernames.add(ftpUser.getUsername());
            }
        } catch (Exception e) {
            log.error("Error loading users from database", e);
        }
        
        return usernames.toArray(new String[0]);
    }

    @Override
    public void delete(String username) throws FtpException {
        try {
            LambdaQueryWrapper<FtpUserDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(FtpUserDO::getUsername, username)
                       .eq(FtpUserDO::getIsDeleted, 0);
            
            FtpUserDO existingUser = ftpUserMapper.selectOne(queryWrapper);
            if (existingUser != null) {
                // 逻辑删除
                FtpUserDO updateUser = new FtpUserDO();
                updateUser.setId(existingUser.getId());
                updateUser.setIsDeleted(1);
                updateUser.setUpdator(1); // 系统更新
                updateUser.setUpdateTime(java.time.LocalDateTime.now());
                
                ftpUserMapper.updateById(updateUser);
                log.info("Deleted FTP user: {}", username);
            } else {
                log.warn("User not found for deletion: {}", username);
            }
        } catch (Exception e) {
            log.error("Failed to delete user: {}", username, e);
            throw new FtpException("Failed to delete user: " + username, e);
        }
    }

    @Override
    public void save(User user) throws FtpException {
        try {
            LambdaQueryWrapper<FtpUserDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(FtpUserDO::getUsername, user.getName())
                       .eq(FtpUserDO::getIsDeleted, 0);
            
            FtpUserDO existingUser = ftpUserMapper.selectOne(queryWrapper);
            
            if (existingUser != null) {
                // 更新现有用户
                existingUser.setPassword(user.getPassword());
                existingUser.setHomeDirectory(user.getHomeDirectory());
                existingUser.setEnabled(user.getEnabled());
                existingUser.setUpdator(1); // 系统更新
                existingUser.setUpdateTime(java.time.LocalDateTime.now());
                
                // 从用户权限中提取信息
                boolean hasWritePermission = false;
                for (Authority authority : user.getAuthorities()) {
                    if (authority instanceof WritePermission) {
                        hasWritePermission = true;
                        break;
                    }
                }
                existingUser.setWritePermission(hasWritePermission);
                
                ftpUserMapper.updateById(existingUser);
                log.info("Updated FTP user: {}", user.getName());
            } else {
                // 创建新用户
                FtpUserDO newUser = new FtpUserDO();
                newUser.setUsername(user.getName());
                newUser.setPassword(user.getPassword());
                newUser.setHomeDirectory(user.getHomeDirectory());
                newUser.setEnabled(user.getEnabled());
                newUser.setWritePermission(false);
                newUser.setMaxConnections(5);
                newUser.setMaxConnectionsPerIp(2);
                newUser.setCreator(1);
                newUser.setUpdator(1);
                newUser.setCreateTime(java.time.LocalDateTime.now());
                newUser.setUpdateTime(java.time.LocalDateTime.now());
                newUser.setIsDeleted(0);
                
                // 从用户权限中提取信息
                boolean hasWritePermission = false;
                for (Authority authority : user.getAuthorities()) {
                    if (authority instanceof WritePermission) {
                        hasWritePermission = true;
                        break;
                    }
                }
                newUser.setWritePermission(hasWritePermission);
                
                ftpUserMapper.insert(newUser);
                log.info("Created new FTP user: {}", user.getName());
            }
        } catch (Exception e) {
            log.error("Failed to save user: {}", user.getName(), e);
            throw new FtpException("Failed to save user: " + user.getName(), e);
        }
    }

    @Override
    public boolean doesExist(String username) throws FtpException {
        return getUserByName(username) != null;
    }

    @Override
    public User authenticate(Authentication authentication) throws AuthenticationFailedException {
        if (authentication instanceof UsernamePasswordAuthentication) {
            UsernamePasswordAuthentication upAuth = (UsernamePasswordAuthentication) authentication;
            String username = upAuth.getUsername();
            String password = upAuth.getPassword();

            try {
                User user = getUserByName(username);
                if (user != null && user.getPassword().equals(password)) {
                    log.info("User authenticated successfully: {}", username);
                    return user;
                }
            } catch (FtpException e) {
                log.error("Error during authentication for user: {}", username, e);
            }
        }
        
        log.warn("Authentication failed for user: {}", 
            authentication instanceof UsernamePasswordAuthentication ? 
            ((UsernamePasswordAuthentication) authentication).getUsername() : "unknown");
        throw new AuthenticationFailedException("Authentication failed");
    }

    @Override
    public String getAdminName() throws FtpException {
        return "admin";
    }

    @Override
    public boolean isAdmin(String username) throws FtpException {
        return "admin".equals(username);
    }
    
    /**
     * 创建用户目录结构
     */
    private void createUserDirectoryStructure(File userHomeDir, String username) {
        try {
            String rootDir = ftpProperties.getServer().getRootDirectory();
            
            // 1. 创建用户私有目录结构
            File privateDir = new File(userHomeDir, "private");
            File inboxDir = new File(userHomeDir, "inbox");
            File outboxDir = new File(userHomeDir, "outbox");

            privateDir.mkdirs();
            inboxDir.mkdirs();
            outboxDir.mkdirs();
            
            // 2. 创建公共共享目录（所有用户可访问）
            File publicDir = new File(rootDir, "public");
            if (!publicDir.exists()) {
                publicDir.mkdirs();
                log.info("Created public shared directory: {}", publicDir.getAbsolutePath());
            }
            
            // 3. 创建到公共目录的符号链接（如果系统支持）
            File publicLink = new File(userHomeDir, "shared");
            if (!publicLink.exists()) {
                try {
                    // 尝试创建符号链接
                    java.nio.file.Files.createSymbolicLink(
                        publicLink.toPath(), 
                        publicDir.toPath()
                    );
                    log.info("Created symbolic link to public directory for user: {}", username);
                } catch (Exception e) {
                    // 如果符号链接失败，创建说明文件
                    File readmeFile = new File(userHomeDir, "README_SHARED.txt");
                    try (java.io.FileWriter writer = new java.io.FileWriter(readmeFile)) {
                        writer.write("公共共享目录位置: " + publicDir.getAbsolutePath() + "\n");
                        writer.write("要访问共享文件，请使用: cd ../../../public\n");
                        writer.write("Public shared directory: " + publicDir.getAbsolutePath() + "\n");
                        writer.write("To access shared files, use: cd ../../../public\n");
                    }
                    log.info("Created README file for public directory access for user: {}", username);
                }
            }
            
            // 4. 创建用户说明文件
            File userReadme = new File(userHomeDir, "README.txt");
            if (!userReadme.exists()) {
                try (java.io.FileWriter writer = new java.io.FileWriter(userReadme)) {
                    writer.write("=== FTP用户目录说明 ===\n");
                    writer.write("用户: " + username + "\n");
                    writer.write("创建时间: " + java.time.LocalDateTime.now() + "\n\n");
                       writer.write("目录结构:\n");
                       writer.write("- private/   : 私有文件目录（仅您可访问）\n");
                       writer.write("- inbox/     : 接收文件目录（其他用户可向此上传）\n");
                       writer.write("- outbox/    : 发送文件目录（您可上传供他人下载）\n");
                       writer.write("- shared/    : 公共共享目录（所有用户可访问）\n\n");
                       writer.write("=== FTP User Directory Guide ===\n");
                       writer.write("User: " + username + "\n");
                       writer.write("Created: " + java.time.LocalDateTime.now() + "\n\n");
                       writer.write("Directory Structure:\n");
                       writer.write("- private/   : Private files (only you can access)\n");
                       writer.write("- inbox/     : Receive files (others can upload here)\n");
                       writer.write("- outbox/    : Send files (you upload for others to download)\n");
                       writer.write("- shared/    : Public shared directory (all users can access)\n");
                }
            }
            
            log.info("Created directory structure for user: {} at {}", username, userHomeDir.getAbsolutePath());
            
        } catch (Exception e) {
            log.error("Failed to create directory structure for user: {}", username, e);
        }
    }
}
